#include "ImgEnhanceWidget.h"
#include "ui_ImgEnhanceWidget.h"
#include "opencv2/opencv.hpp"
#include "opencv2/core/utils/logger.hpp"

#include <QDebug>


#define CHECK(status)                                                                                                  \
    do                                                                                                                 \
{                                                                                                                  \
    auto ret = (status);                                                                                           \
    if (ret != 0)                                                                                                  \
{                                                                                                              \
    std::cerr << "Cuda failure: " << ret << std::endl;                                                         \
    abort();                                                                                                   \
    }                                                                                                              \
    } while (0)

#define CHECK_RETURN_W_MSG(status, val, errMsg)                                                                        \
    do                                                                                                                 \
{                                                                                                                  \
    if (!(status))                                                                                                 \
{                                                                                                              \
    std::cerr << errMsg << " Error in " << __FILE__ << ", function " << FN_NAME << "(), line " << __LINE__     \
    << std::endl;                                                                                    \
    return val;                                                                                                \
    }                                                                                                              \
    } while (0)

#define CHECK_RETURN(status, val) CHECK_RETURN_W_MSG(status, val, "")


ImgEnhanceWidget::ImgEnhanceWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ImgEnhanceWidget)
{
    ui->setupUi(this);
    ui->infoText->setFontWeight(QFont::Bold);
    ui->infoText->setFontPointSize(12);
    ui->comboBox_Workspace->setCurrentIndex(3);
//    ui->lineEdit_FileName->setText("F:/dnn-prj/moduleparam/MixUNet1.onnx");
//    ui->lineEdit_TRTFilePath->setText("F:/dnn-prj/moduleparam/MixUNet1.onnx.trt");
//    ui->lineEdit_ImgPath->setText("F:/dnn-prj/oct_img/11");

    QSettings setting("runvar.ini",QSettings::IniFormat);
    setting.beginGroup("LineEdit");
    ui->lineEdit_FileName->setText(setting.value(ui->lineEdit_FileName->objectName()).toString());
    ui->lineEdit_TRTFilePath->setText(setting.value(ui->lineEdit_TRTFilePath->objectName()).toString());
    ui->lineEdit_ImgPath->setText(setting.value(ui->lineEdit_ImgPath->objectName()).toString());
    setting.endGroup();

    m_verboseBox.setParent(nullptr);

    m_onnxRtObj = new OnnxRuntimeObj;


    connect(m_onnxRtObj,SIGNAL(toastInfo(QString,QString)),
            this,SLOT(toastInfo(QString,QString))
            );

    connect(&m_trtLogger,SIGNAL(toastInfo(QString,QString)),
            this,SLOT(toastInfo(QString,QString)),
            Qt::QueuedConnection
            );

    connect(&m_trtLogger,SIGNAL(toastVerbose(QString,QString)),
            this,SLOT(toastVerbose(QString,QString)),
            Qt::QueuedConnection
            );

    connect(ui->btnClearInfo,SIGNAL(clicked()),
            ui->infoText,SLOT(clear())
            );

    cv::utils::logging::setLogLevel(
                cv::utils::logging::LOG_LEVEL_WARNING);  //  警告级以上信息才显示

}

ImgEnhanceWidget::~ImgEnhanceWidget()
{
    delete ui;
}

void ImgEnhanceWidget::closeEvent(QCloseEvent *event)
{
    Q_UNUSED(event)
    m_verboseBox.close();
}

///
/// \brief toastInfo
/// \param info
/// \param color
///弹出信息到 信息栏
void ImgEnhanceWidget::toastInfo(QString info, QString color)
{

    if(ui->infoText->document()->blockCount()>=200){
        ui->infoText->clear();
    }
    ui->infoText->setTextColor(QColor(color));
    ui->infoText->append(info);
    if(!ui->infoText->hasFocus()){
        QTextCursor textCursor=ui->infoText->textCursor();
        textCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
        textCursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
        ui->infoText->setTextCursor(textCursor);
    }

}

void ImgEnhanceWidget::toastVerbose(QString info, QString color)
{
    m_verboseBox.setTextColor(QColor(color));
    m_verboseBox.append(info);
    if(!m_verboseBox.hasFocus()){
        QTextCursor textCursor=m_verboseBox.textCursor();
        textCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
        textCursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
        m_verboseBox.setTextCursor(textCursor);
    }
//    m_verboseBox.activateWindow();
    m_verboseBox.show();
}

void ImgEnhanceWidget::on_btnGetFileName_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Select ONNX File"),
                                                    ui->lineEdit_FileName->text(),
                                                    tr("ONNX File (*.onnx);;"
                                                       "All File (*.*)")
                                                    );

    if(fileName.isNull() || fileName.isEmpty()) return;

    QFileInfo info(fileName);
    if(!info.exists()){
        toastInfo(QString("File '%1' not exists").arg(fileName),"red");
        return;
    }
    fileName = QDir::toNativeSeparators(fileName);

    ui->lineEdit_FileName->setText(fileName);
    QSettings setting("runvar.ini",QSettings::IniFormat);
    setting.beginGroup("LineEdit");
    setting.setValue(ui->lineEdit_FileName->objectName(),ui->lineEdit_FileName->text());
    setting.sync();
    setting.endGroup();
}

void ImgEnhanceWidget::on_btnGetTRTFileName_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Select TensorRT serialize file"),
                                                    ui->lineEdit_TRTFilePath->text(),
                                                    tr("TRT serialize file (*.trt);;"
                                                       "All File (*.*)")
                                                    );

    if(fileName.isNull() || fileName.isEmpty()) return;

    QFileInfo info(fileName);
    if(!info.exists()){
        toastInfo(QString("File '%1' not exists").arg(fileName),"red");
        return;
    }
    fileName = QDir::toNativeSeparators(fileName);

    ui->lineEdit_TRTFilePath->setText(fileName);
    QSettings setting("runvar.ini",QSettings::IniFormat);
    setting.beginGroup("LineEdit");
    setting.setValue(ui->lineEdit_TRTFilePath->objectName(),ui->lineEdit_TRTFilePath->text());
    setting.sync();
    setting.endGroup();
}

void ImgEnhanceWidget::on_btnGetImagesPath_clicked()
{
    QString dirstr=QFileDialog::getExistingDirectory(nullptr,
                                                     tr("Select Images Directory "),
                                                     ui->lineEdit_ImgPath->text()
                                                     );

    if(dirstr.isNull() || dirstr.isEmpty()) return;
    dirstr = QDir::toNativeSeparators(dirstr);
    ui->lineEdit_ImgPath->setText(dirstr);
    QSettings setting("runvar.ini",QSettings::IniFormat);
    setting.beginGroup("LineEdit");
    setting.setValue(ui->lineEdit_ImgPath->objectName(),ui->lineEdit_ImgPath->text());
    setting.sync();
    setting.endGroup();
}


void ImgEnhanceWidget::on_btnRunByOrt_clicked()
{
    QString filename = ui->lineEdit_FileName->text();
    QFileInfo info(filename);
    if(!info.exists()){
        toastInfo(QString("File '%1' not exists!").arg(filename),"red");
        return;
    }

    QString imgdirname = ui->lineEdit_ImgPath->text();
    QDir imgdir(imgdirname);
    QStringList nameFilters;
    nameFilters<<"*.png"<<"*.jpg"<<"*.bmp";

    if(!imgdir.exists()){
        toastInfo(QString("Invaild Images Dir '%1' !").arg(imgdirname),"red");
        return;
    }

    QStringList imgfilesname = imgdir.entryList(nameFilters,
                                                QDir::Files|QDir::Readable,
                                                QDir::SortFlag::Name
                                                );

    int imgcnt = imgfilesname.count();
    if(imgcnt<1){
        toastInfo(QString("No Image in Dir '%1' !").arg(imgdir.absolutePath()),"red");
        return;
    }

    bool initok = m_onnxRtObj->initSession(filename);

    if(!initok) return;

    std::vector<int64_t> inshape;
    if(!m_onnxRtObj->getSessionInputShape(inshape)) return;
    if(inshape[0]!=1 || inshape[1]!=1 || inshape[2]<1 || inshape[3]<1) return;

    std::vector<int64_t> outshape;
    float *outputfloatptr = nullptr;
    for (int i = 0; i < imgcnt; ++i) {
        QString imgfilename = QDir::toNativeSeparators(imgdir.absolutePath())+QDir::separator()+imgfilesname[i];
        //        qDebug()<<imgfilename;
        cv::Mat orgimg = cv::imread(imgfilename.toLocal8Bit().toStdString(),cv::IMREAD_GRAYSCALE);
        if(orgimg.data==nullptr) continue;
        if(orgimg.empty()) continue;

        cv::MatSize orgsize = orgimg.size;

        cv::imshow("orgin img",orgimg);
//        cv::waitKey(1);

        cv::Mat inputimg;
        cv::resize(orgimg,inputimg,cv::Size(static_cast<int>(inshape[2]),static_cast<int>(inshape[3])));
        inputimg.convertTo(inputimg,CV_32FC1,1/255.0);

        cv::imshow("input img",inputimg);
//        cv::waitKey(1);

        outputfloatptr = nullptr;
        outshape.clear();
        bool inferok=m_onnxRtObj->sessionInfer(inputimg.ptr<float>(),{inshape[0],inshape[1],inshape[2],inshape[3]},
                                               &outputfloatptr,outshape);
        if(!inferok) continue;
        if(!outputfloatptr) continue;
        if(outshape.size()!=4){
            delete [] outputfloatptr;
            continue;
        }

        cv::Mat output(cv::Size(static_cast<int>(outshape[2]),static_cast<int>(outshape[3])),
                CV_32FC1,
                outputfloatptr
                );

        cv::Mat outimg;
        cv::resize(output,outimg,orgsize());
        outimg.convertTo(outimg,CV_8UC1,255);

        cv::imshow("output",output);
//        cv::waitKey(1);

        cv::imshow("output img",outimg);


        delete [] outputfloatptr;

        int key = cv::waitKey(1);

        if(key==27) break;
    }

    cv::destroyAllWindows();


}

void ImgEnhanceWidget::on_btnGenTRTBin_clicked()
{
    QString filename = ui->lineEdit_FileName->text();
    QFileInfo info(filename);
    if(!info.exists()){
        toastInfo(QString("File '%1' not exists!").arg(filename),"red");
        return;
    }

    //创建builder
    nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(m_trtLogger);
    Q_ASSERT("create nvinfer1::IBuilder" && (builder!=nullptr));

    //创建networkdefinition
    const auto explicitBatch =
            1U << static_cast<uint32_t>(
                      nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH
                      );    //设置显式指定批大小 和 是否显式指定精度kEXPLICIT_PRECISION 按位或后左移1
    //kEXPLICIT_BATCH用于指定形状是可变的

    // createNetworkV2(0U) 等于 createNetwork（）的行为


    nvinfer1::INetworkDefinition* networkdef = builder->createNetworkV2(explicitBatch);
    Q_ASSERT("create nvinfer1::INetworkDefinition" && (networkdef!=nullptr));

    //创建配置
    nvinfer1::IBuilderConfig* buildcfg = builder->createBuilderConfig();
    Q_ASSERT("create nvinfer1::IBuilderConfig" && (buildcfg!=nullptr));

    //创建解释器
    nvonnxparser::IParser* parser = nvonnxparser::createParser(*networkdef, m_trtLogger);
    Q_ASSERT("create nvinfer1::IParser" && (parser!=nullptr));

    //解释onnx格式文件
    bool parseOk = parser->parseFromFile(filename.toLocal8Bit().data(),
                                         static_cast<int>(LoggerForTRT::Severity::kINFO));

    if(!parseOk){
        toastInfo(QString("Parser ONNX File '%1' failed!").arg(filename),"red");
    }

    bool genSerializeFileOk = false;
    m_trtLogger.setIsBuildingEngine(true);
    m_verboseBox.resize(400,600);
    m_verboseBox.show();
    do{
        //检查模型相关属性
        qApp->processEvents();
        if(networkdef->getNbInputs()!=1){
            toastInfo("onnx model inputs !=1 ","red");
            break;
        }
        if(networkdef->getNbOutputs()!=1){
            toastInfo("onnx model outputs !=1 ","red");
            break;
        }

        const nvinfer1::DataType typeList[]={nvinfer1::DataType::kFLOAT,nvinfer1::DataType::kHALF,
                                             nvinfer1::DataType::kINT8,nvinfer1::DataType::kINT32,
                                             nvinfer1::DataType::kBOOL};
        nvinfer1::DataType type = networkdef->getInput(0)->getType();
        if(type!=typeList[ui->comboBox_InType->currentIndex()]){
            toastInfo(QString("onnx model input data type is not %1").arg(ui->comboBox_InType->currentText()),"red");
            break;
        }

        type = networkdef->getOutput(0)->getType();
        if(type!=typeList[ui->comboBox_OutType->currentIndex()]){
            toastInfo(QString("onnx model output data type is not %1").arg(ui->comboBox_OutType->currentText()),"red");
            break;
        }

        //获取输入输出的维度
        bool dimsIsok = true;
        bool isDynamic_shape = false;
        nvinfer1::Dims inputdims = networkdef->getInput(0)->getDimensions();
        nvinfer1::Dims outputdims = networkdef->getOutput(0)->getDimensions();
        dimsIsok = dimsIsok && (inputdims.nbDims==4);
        dimsIsok = dimsIsok && (outputdims.nbDims==4);
        dimsIsok = dimsIsok && (inputdims.d[1]==1);
        dimsIsok = dimsIsok && (outputdims.d[1]==1);

        if(inputdims.d[0]==-1 && inputdims.d[2]==-1 && inputdims.d[3]==-1){
            isDynamic_shape = true;
            dimsIsok = dimsIsok && (outputdims.d[0]==-1 && outputdims.d[2]==-1 && outputdims.d[3]==-1);
        }else if(inputdims.d[0]>0 || inputdims.d[2]>0 || inputdims.d[3]>0){
            isDynamic_shape = false;
            if(inputdims.d[0]!=1 || outputdims.d[0]!=1){
                dimsIsok = false;
            }
            dimsIsok = dimsIsok && (outputdims.d[2]>0 && outputdims.d[3]>0);

        }

        if(!dimsIsok){
            toastInfo("onnx model input output dims invalid!","red");
            break;
        }

        if(isDynamic_shape){
            //创建优化器 用于动态形状维度     context.setOptimizationProfile(0)
            // builder会自动秋放该指针
            int dimsopt[3][4]={
                {1,1,256,256},
                {1,1,512,512},
                {1,1,512,1024}
            };

            for (int j = 0; j < 3; ++j) {
                for (int i = 0; i < 4; ++i) {
                    int t;
                    bool ok;
                    t = ui->tableWidget_OptProfile->item(j,i)->text().toInt(&ok);
                    if(!ok || t<1){
                        toastInfo("Invalid Optimization Profile Value In Table","red");
                    }
                    dimsopt[j][i] = t;
//                    qDebug()<<t;
                }
            }

            nvinfer1::IOptimizationProfile* profile = builder->createOptimizationProfile();
            Q_ASSERT("create nvinfer1::IOptimizationProfile" && (profile!=nullptr));

            std::string inname = networkdef->getInput(0)->getName();
            profile->setDimensions(inname.c_str(),
                                   nvinfer1::OptProfileSelector::kMIN,
                                   nvinfer1::Dims4(dimsopt[0][0],dimsopt[0][1],dimsopt[0][2],dimsopt[0][3]));
            profile->setDimensions(inname.c_str(),
                                   nvinfer1::OptProfileSelector::kOPT,
                                   nvinfer1::Dims4(dimsopt[1][0],dimsopt[1][1],dimsopt[1][2],dimsopt[1][3]));
            profile->setDimensions(inname.c_str(),
                                   nvinfer1::OptProfileSelector::kMAX,
                                   nvinfer1::Dims4(dimsopt[2][0],dimsopt[2][1],dimsopt[2][2],dimsopt[2][3]));

            //如果有动态维度的输入输出 需要添加优化器
            //可以添加多个优化器 第一个添加的索引号为0
            //返回值为 当次添加的优化器索引  后面的 context可选择优化器
            buildcfg->addOptimizationProfile(profile);
        }

        int maxbatchsize = ui->spinBox_MaxBatchSize->value();
        size_t workspace = 1024LL*1024*1024;
        workspace = workspace * static_cast<size_t>(ui->comboBox_Workspace->currentIndex() + 1);
        builder->setMaxBatchSize(maxbatchsize);   //设置最大的批数量
        buildcfg->setMemoryPoolLimit(nvinfer1::MemoryPoolType::kWORKSPACE, workspace); //设置最大占用内存

        //获取保存 TRT序列化文件路径
        QString saveTrtfilename = QFileDialog::getSaveFileName(this, tr("Save TRT File"),
                                                               filename,
                                                               tr("TensorRT Serialize File (*.trt)"));

        if(saveTrtfilename.isNull() || saveTrtfilename.isEmpty()){
            break;
        }

        bool hasFastFp16 = builder->platformHasFastFp16();
        if(hasFastFp16){
            toastInfo("Support FP16 :Yes","green");
            QMessageBox msgbox;
            msgbox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
            msgbox.setText("Would you like to build tensorrt enging in FP16 mode?");
            int ret = msgbox.exec();
            if(ret==QMessageBox::Yes){
                buildcfg->setFlag(nvinfer1::BuilderFlag::kFP16);    //推荐使用FP16加速 但实际编译不一定是
//                buildcfg->setFlag(nvinfer1::BuilderFlag::kSTRICT_TYPES);    //强制一定使用FP16
            }
        }else{
            toastInfo("Support FP16 :No","black");
        }

        toastInfo("Start to build tensorrt engine,please wait!","green");

        //编译和构建引擎
        m_verboseBox.hide();
        QMessageBox msgbox(this);
        msgbox.setWindowModality(Qt::WindowModal);
        msgbox.setStandardButtons(QMessageBox::Ok|QMessageBox::Abort);
        msgbox.setText("building tensorrt engine,please wait!");
        connect(this,SIGNAL(trtEngineBuilded()),
                &msgbox,SLOT(close()),
                Qt::QueuedConnection
                );

        QThreadPool threadpool;
        QThread *buildthread=nullptr;
        nvinfer1::IHostMemory* serializedModel = nullptr;
        threadpool.setExpiryTimeout(100);
        QFuture<void> future = QtConcurrent::run(&threadpool,[&]() {
            buildthread=QThread::currentThread();
            serializedModel = builder->buildSerializedNetwork(*networkdef, *buildcfg);
            emit this->trtEngineBuilded();
        });

        //等待构建结束
        while(!future.isFinished()){
            int ret = msgbox.exec();
            if(ret == QMessageBox::Abort && future.isStarted() && !future.isFinished()){
                if(buildthread && !buildthread->isFinished()){
                    buildthread->quit();
                    try {
                        buildthread->terminate();
                        buildthread->wait(2000);
                    } catch (...) {
                    }
                    if(serializedModel){
                        delete serializedModel;
                        serializedModel=nullptr;
                    }
                    qApp->quit();
                    break;
                }
            }
        }
        disconnect(this,SIGNAL(trtEngineBuilded()),
                   &msgbox,SLOT(close())
                   );


        Q_ASSERT("Force to Abort when building tensorrt engin" && future.isFinished());

        toastInfo("build tensorrt engine end!","green");

        if(!serializedModel){
            toastInfo("build tensorrt serialized model failed!","red");
            break;
        }

        QFile saveTrtFile(saveTrtfilename);
        if(!saveTrtFile.open(QIODevice::WriteOnly|QIODevice::Truncate)){
            delete serializedModel;
            serializedModel = nullptr;
            toastInfo(QString("open file '%1' to write failed!").arg(saveTrtfilename),"red");
            break;
        }

        try {
            saveTrtFile.write(reinterpret_cast<const char *>(serializedModel->data()),
                              static_cast<qint64>(serializedModel->size())
                              );
        } catch (...) {
            toastInfo(QString("write file '%1' failed!").arg(saveTrtfilename),"red");
            break;
        }

        saveTrtFile.flush();
        saveTrtFile.close();
        delete serializedModel;
        serializedModel = nullptr;

        genSerializeFileOk = true;
        ui->lineEdit_TRTFilePath->setText(QDir::toNativeSeparators(saveTrtfilename));
        m_verboseBox.close();
    }while(0);

    if(parser) delete parser;
    if(buildcfg) delete buildcfg;
    if(networkdef) delete networkdef;
    if(builder) delete builder;

    m_trtLogger.setIsBuildingEngine(false);
}

void ImgEnhanceWidget::on_btnLoadAndRunTRT_clicked()
{
    QString filename = ui->lineEdit_TRTFilePath->text();

    QFileInfo info(filename);
    filename = QDir::toNativeSeparators(info.absoluteFilePath());
    if(!info.exists()){
        toastInfo(QString("File '%1' not exists!").arg(filename),"red");
        return;
    }

    QString imgdirname = ui->lineEdit_ImgPath->text();
    QDir imgdir(imgdirname);
    QStringList nameFilters;
    nameFilters<<"*.png"<<"*.jpg"<<"*.bmp";

    if(!imgdir.exists()){
        toastInfo(QString("Invaild Images Dir '%1' !").arg(imgdirname),"red");
        return;
    }

    QStringList imgfilesname = imgdir.entryList(nameFilters,
                                                QDir::Files|QDir::Readable,
                                                QDir::SortFlag::Name
                                                );

    int imgcnt = imgfilesname.count();
    if(imgcnt<1){
        toastInfo(QString("No Image in Dir '%1' !").arg(imgdir.absolutePath()),"red");
        return;
    }

    m_verboseBox.resize(400,600);
    m_verboseBox.show();
    //打开trt文件 加载数据
    QFile trtfile(filename);
    if(!trtfile.open(QIODevice::ReadOnly)){
        toastInfo(QString("open file '%1' to read failed!").arg(filename),"red");
        return;
    }

    qint64 filelen = trtfile.size();
    char * data = new char[static_cast<size_t>(filelen)];

    if(trtfile.read(data,filelen)!=filelen){
        delete [] data;
        trtfile.close();
        toastInfo(QString("read file '%1' data failed!").arg(filename),"red");
        return;
    }

    trtfile.close();

    //从序列化数据中 恢复tensorrt 引擎
    nvinfer1::IRuntime *runtime = nvinfer1::createInferRuntime(m_trtLogger);
    Q_ASSERT("create nvinfer1::IRuntime" && (runtime!=nullptr));
    nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(data, static_cast<size_t>(filelen));
    Q_ASSERT("create nvinfer1::ICudaEngine" && (engine!=nullptr));
    if(data) delete [] data;
    delete runtime;

    nvinfer1::IExecutionContext* context = engine->createExecutionContext();

    bool dimsok = true;
    bool checkok = false;
    int inputindex = 0;
    int outputindex = 1;
    nvinfer1::Dims4 indims(0,0,0,0);
    nvinfer1::Dims4 outdims(0,0,0,0);

    do{
        if(engine->getNbBindings()!=2){
            toastInfo("tensorrt engine bindings not equal to 2!","red");
            break;
        }
        if(!engine->bindingIsInput(inputindex)){
            inputindex=1;
            outputindex=0;
        }

        if(!engine->bindingIsInput(inputindex)){
            toastInfo("tensorrt engine bindings index invalid!","red");
            break;
        }

        nvinfer1::DataType type = engine->getBindingDataType(inputindex);
        if(type != nvinfer1::DataType::kFLOAT){
            toastInfo("tensorrt engine bindings input data type is not float32!","red");
            break;
        }
        type = engine->getBindingDataType(outputindex);
        if(type != nvinfer1::DataType::kFLOAT){
            toastInfo("tensorrt engine bindings output data type is not float32!","red");
            break;
        }

//        context->setOptimizationProfileAsync(0, nullptr);

        nvinfer1::Dims xdims = context->getBindingDimensions(inputindex);
        if(xdims.nbDims==4 && xdims.d[1]==1 && (xdims.d[0]<0 || xdims.d[2]<0 || xdims.d[3]<0)){
            nvinfer1::Dims4 defdims(1,1,512,512);
            int optindex = context->getOptimizationProfile();
            nvinfer1::Dims optdims = engine->getProfileDimensions(inputindex,optindex,nvinfer1::OptProfileSelector::kOPT);
            if(optdims.nbDims==4 && optdims.d[1]==1){
                defdims.d[2]=optdims.d[2];
                defdims.d[3]=optdims.d[3];
            }
            context->setBindingDimensions(inputindex,defdims);
            xdims=defdims;
        }

        nvinfer1::Dims ydims;
        ydims.nbDims = 0;
        for (int i = 0; i < 4; ++i) {
            ydims.d[i] = 0;
        }
        if(context->allInputDimensionsSpecified()){
            ydims = context->getBindingDimensions(outputindex);
            if(ydims.nbDims!=4){
                dimsok=false;
            }else{
                qDebug() << ydims.nbDims << ydims.d[0]<< ydims.d[1]<< ydims.d[2]<< ydims.d[3];
                dimsok=dimsok && ydims.d[0]==1;
                dimsok=dimsok && ydims.d[1]==1;
                dimsok=dimsok && ydims.d[2]>0;
                dimsok=dimsok && ydims.d[3]>0;
            }
        }

        if(xdims.nbDims!=4){
            dimsok=false;
        }
        dimsok=dimsok && xdims.d[1]==1;

        dimsok=dimsok && xdims.d[0]==1;
        dimsok=dimsok && xdims.d[2]>0;
        dimsok=dimsok && xdims.d[3]>0;

        if(!dimsok){
            toastInfo("tensorrt engine input or output dims invalid!","red");
        }else{
            dynamic_cast<nvinfer1::Dims&>(indims)=xdims;
            dynamic_cast<nvinfer1::Dims&>(outdims)=ydims;
        }

        checkok = true;
    }while(0);

    if(!dimsok || !checkok){
        delete context;
        delete engine;
        return;
    }

    //创建cuda内存
    checkok = false;
    void* cudaBuffers[2]={nullptr};
    size_t insize = static_cast<size_t>(indims.d[0]);
    size_t outsize = static_cast<size_t>(outdims.d[0]);
    insize=insize*static_cast<size_t>(indims.d[1])*static_cast<size_t>(indims.d[2])*static_cast<size_t>(indims.d[3]);
    outsize=outsize*static_cast<size_t>(outdims.d[1])*static_cast<size_t>(outdims.d[2])*static_cast<size_t>(outdims.d[3]);

    cudaError_t cudaret = cudaMalloc(&cudaBuffers[0],insize*4);
    checkok = (cudaret==0);
    if(!checkok){
        toastInfo("cuda Memory allocate failed!","red");
    }
    cudaret = cudaMalloc(&cudaBuffers[1],outsize*4);
    checkok = checkok && (cudaret==0);
    if(!checkok){
        toastInfo("cuda Memory allocate failed!","red");
    }

    cudaStream_t stream=nullptr;
    cudaStreamCreate(&stream);
    checkok = checkok && (cudaret==0);
    if(!checkok){
        toastInfo("create cuda Stream failed!","red");
    }



    //输入数据 运行模型 显示数据
    if(checkok){
//        std::vector<int64_t> outshape;
        float *outputfloatptr = new float[outsize];
        QTime time;
        int framecnt = 0;
        time.restart();
        for (int i = 0; i < imgcnt; ++i) {
            QString imgfilename = QDir::toNativeSeparators(imgdir.absolutePath())+QDir::separator()+imgfilesname[i];
            //        qDebug()<<imgfilename;
            cv::Mat orgimg = cv::imread(imgfilename.toLocal8Bit().toStdString(),cv::IMREAD_GRAYSCALE);
            if(orgimg.data==nullptr) continue;
            if(orgimg.empty()) continue;

            cv::MatSize orgsize = orgimg.size;

            cv::imshow("orgin img",orgimg);
//            int key = cv::waitKey(1);

            cv::Mat inputimg;
            cv::resize(orgimg,inputimg,cv::Size(indims.d[2],indims.d[3]));
            inputimg.convertTo(inputimg,CV_32FC1,1/255.0);

            cv::imshow("input img",inputimg);
//            key = cv::waitKey(1);

//            qDebug()<<inputimg.total();
            //复制主机缓冲区数据到 显卡内存
            auto ret = cudaMemcpyAsync(cudaBuffers[0],
                    inputimg.ptr<float>(),
                    inputimg.total()*4,
                    cudaMemcpyHostToDevice, stream);
            if(ret){
                toastInfo("cudaMemcpyAsync failed!","red");
                continue;
            }

            //计算 获取结果
            if(!context->enqueue(1, cudaBuffers, stream, nullptr)){ //执行推理
                toastInfo("context->enqueu failed!","red");
                cudaStreamSynchronize(stream);
                continue;
            }

            ret = cudaMemcpyAsync(outputfloatptr,
                                  cudaBuffers[1],
                    outsize * 4,
                    cudaMemcpyDeviceToHost, stream);
            if(ret){
                toastInfo("cudaMemcpyAsync failed!","red");
                cudaStreamSynchronize(stream);
                continue;
            }

            //等待执行完成
            auto err = cudaStreamSynchronize(stream);
            if(err!=cudaSuccess){
                QString errstr(cudaGetErrorString(err));
                toastInfo(errstr,"red");
            }

            cv::Mat output(cv::Size(outdims.d[2],outdims.d[3]),
                    CV_32FC1,
                    outputfloatptr
                    );

            cv::Mat outimg;
            cv::resize(output,outimg,orgsize());
            outimg.convertTo(outimg,CV_8UC1,255);

            cv::imshow("output",output);
//            key = cv::waitKey(1);

            cv::imshow("output img",outimg);

            int key = cv::waitKey(1);

            if(key==27) break;

            framecnt++;
            if(time.elapsed()>1000){
                float framerate = framecnt;
                framerate = 1000.0f*framecnt / time.elapsed();
                QString info("frame rate = %1");
                toastInfo(info.arg(static_cast<double>(framerate),0,'f',2,QChar('0')));
                time.restart();
                framecnt=0;
            }
        }
        delete [] outputfloatptr;
        cv::destroyAllWindows();
    }


    if(stream){
        cudaStreamSynchronize(stream);
        cudaStreamDestroy(stream);
    }

    if(cudaBuffers[0]){
        cudaFree(cudaBuffers[0]);
    }

    if(cudaBuffers[1]){
        cudaFree(cudaBuffers[1]);
    }

    delete context;
    delete engine;
    m_verboseBox.close();
}















